package pri.damai.xiaowu.auth.security.loginlogic.base;

import pri.damai.xiaowu.auth.enums.ResultEnum;
import pri.damai.xiaowu.auth.security.loginlogic.LoginTypeEnums;
import pri.damai.xiaowu.auth.security.model.LoginData;
import pri.damai.xiaowu.auth.security.model.UserInfo;
import org.springframework.security.authentication.AuthenticationServiceException;
import pri.damai.xiaowu.common.core.exception.GlobalException;

import java.util.Optional;

/**
 * 自定义认证逻辑抽象类
 * @Desc 此部分逻辑采用工厂+策略+模板模式。
 *       后续需要扩展登录方式时：
 *          1. 增加需要的登录参数
 *          2. 写一个子类继承此类，重写此类的方法即可。
 * @Author DaMai
 * @Date 2021/10/13 17:47
 * 但行好事，莫问前程。
 */
public abstract class AbstractLoginLogic {

    /**
     * 核心登录校验逻辑
     * @apiNote [附加描述]
     * @param loginData 登录参数
     * @return org.springframework.security.core.userdetails.UserDetails
     * @author DaMai
     * @date 2021/5/7 14:51
     */
    public UserInfo authenticate(LoginData loginData) {

        authenticateBefore(loginData);

        UserInfo details = Optional
                .ofNullable(getUserDetails(loginData))
                .orElseThrow(() -> new GlobalException(ResultEnum.USER_NOT_FOUND));

        authenticateAfter(details);

        return details;
    }

    /**
     * 获取本类支持的登录方式
     * @apiNote 留给子类实现
     * @return java.lang.String
     * @author DaMai
     * @date 2021/5/7 14:44
     */
    public abstract LoginTypeEnums getSupportLoginType();

    /**
     * 前置操作
     * @apiNote 留给子类实现(例如校验某些参数不为空)
     * @param loginData 登录参数
     * @author DaMai
     * @date 2021/5/7 14:46
     */
    public abstract void authenticateBefore(LoginData loginData);

    /**
     * 后置操作。
     * @apiNote 允许子类实现，对用户登录认证通过后，进行后置操作。
     * @param userDetails 用户信息
     * @author DaMai
     * @date 2021/5/17 14:44
     */
    public void authenticateAfter(UserInfo userDetails) {
    }

    /**
     * 通过校验之后，获取用户信息
     * @apiNote [附加描述]
     * @param loginData 登录参数
     * @return org.springframework.security.core.userdetails.UserDetails
     * @author DaMai
     * @date 2021/5/7 14:48
     */
    public abstract UserInfo getUserDetails(LoginData loginData);

    protected void throwAuthException(GlobalException globalException) {
        throw new AuthenticationServiceException(globalException.getMsg());
    }

    protected void ifTureThrowAuthException(boolean flag,String msg) {
        if (flag) {
            throw new AuthenticationServiceException(msg);
        }
    }
}
